#include "PageCache.h"

PageCache PageCache::_sInst;

Span *PageCache::NewSpan(size_t k)
{
    assert(k > 0 && k < NPAGES);
    // 先检查 k页的桶有没有空间
    if (!_spanList[k].Empty())
    {
        return _spanList->PopFront();
    }
    // 检查后面有没有 span, 如果有可以进行切分
    for (size_t i = k + 1; i < NPAGES; i++)
    {
        if (!_spanList[i].Empty())
        {
            Span *nSpan = _spanList[i].PopFront();
            Span *kSpan = new Span;

            // 在nspan的头部切分一个k页下来
            // k页的span返回
            // 将nspan再挂回相应的位置
            kSpan->_pageId = nSpan->_pageId;
            kSpan->_n = k;

            nSpan->_pageId += k;
            nSpan->_n -= k;

            _spanList[nSpan->_n].PushFront(nSpan);

            // 建立 id 和 span的映射,方便 central cache回收小块内存时,查找对应的span
            for (PAGE_ID i = kSpan->_pageId; i < kSpan->_n; ++i)
            {
                _idSpanMap[kSpan->_pageId + i] = kSpan;
            }
            return kSpan;
        }
    }

    // 走到这里就说明后面都没有符合要求的大页 span
    // 这个事后就找堆要一个128页的span （systemAllocate）
    auto bigSpan = new Span;
    void *ptr = SystemAlloc(NPAGES - 1);

    bigSpan->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT;
    bigSpan->_n = NPAGES - 1;

    _spanList[bigSpan->_n].PushFront(bigSpan);
    // zdl:: 这里设计得十分的巧妙
    return NewSpan(k);
}
Span *PageCache::MapObjectToSpan(void *obj)
{
    PAGE_ID id = ((PAGE_ID)obj >> PAGE_SHIFT);
    auto ret = _idSpanMap.find(id);
    if (ret != _idSpanMap.end())
    {
        return ret->second;
    }
    else
    {
        assert(false);
        return nullptr;
    }
}

void PageCache::ReleaseSpanToPagecache(Span *span)
{

}

